﻿// JScript File
/// <reference path="_namespace.js" />
/// <reference path="Matrix.js" />


/*****************************************************************************
Ajax library class definition. Kevin Robinson 2006.
Class: ajax.math.Vector3
/*****************************************************************************/

ajax.lang.addNamespace("ajax.math");


//-----------------------------------------------------------------------------
ajax.math.Vector3 = function(x, y, z)
{///<param name="x" type="number"/>
 ///<param name="y" type="number"/>
 ///<param name="z" type="number"/>
    // Remove inheritance for speed
    //ajax.math.Vector3.superConstructor.call(this);        
    this.x = x || 0;
    this.y = y || 0;
    this.z = z || 0;
        
    // Hook into statics
    this.sign       = ajax.math.Vector3.sign;    

}

//-----------------------------------------------------------------------------
//ajax.lang.extend("ajax.math.Vector3", "ajax.BaseObject"); // Inherit
//-----------------------------------------------------------------------------

// Members...

ajax.math.Vector3.create = function(x, y, z)
{///<returns type="ajax.math.Vector3"/>
    return new ajax.math.Vector3(x, y, z);
}

ajax.math.Vector3.prototype.copyValuesFrom = function(vec)
{
    this.x = vec.x;
    this.y = vec.y;
    this.z = vec.z;
}

//-----------------------------------------------------------------------------
// Statics
ajax.math.Vector3.createFrom = function(vectorToCopy)
{///<returns type="ajax.math.Vector3"/>
    var vec = vectorToCopy;
    return new ajax.math.Vector3(vec.x, vec.y, vec.z);
}

//-----------------------------------------------------------------------------
ajax.math.Vector3.sign = function(val)
{
	if (val > 0)
		return 1;
	else
		return -1;
}

//-----------------------------------------------------------------------------
ajax.math.Vector3.min = function(value1, value2)
{///<summary>Returns a vector that contains the lowest value from each matching pair of components.</summary>
 ///<param name="value1" type="ajax.math.Vector3"/>
 ///<param name="value2" type="ajax.math.Vector3"/>
    var vector = new ajax.math.Vector3();
    vector.x = (value1.x < value2.x) ? value1.x : value2.x;
    vector.y = (value1.y < value2.y) ? value1.y : value2.y;
    vector.z = (value1.z < value2.z) ? value1.z : value2.z;
    return vector;
}

//-----------------------------------------------------------------------------
ajax.math.Vector3.max = function(value1, value2)
{///<summary>Returns a vector that contains the highest value from each matching pair of components.</summary>
    ///<param name="value1" type="ajax.math.Vector3"/>
    ///<param name="value2" type="ajax.math.Vector3"/>
    var vector = new ajax.math.Vector3();
    vector.x = (value1.x > value2.x) ? value1.x : value2.x;
    vector.y = (value1.y > value2.y) ? value1.y : value2.y;
    vector.z = (value1.z > value2.z) ? value1.z : value2.z;
    return vector;
}

//-----------------------------------------------------------------------------
ajax.math.Vector3.clamp = function(value1, min, max)
{///<param name="value1" type="ajax.math.Vector3"/>
 ///<param name="min" type="ajax.math.vector3"/>
 ///<param name="max" type="ajax.math.Vector3"/>
 ///<returns type="ajax.math.Vector3">Returns a vector restricted to the min/max.</returns>
    var x = value1.x;
    x = (x > max.x) ? max.x : x;
    x = (x < min.x) ? min.x : x;
    var y = value1.y;
    y = (y > max.y) ? max.y : y;
    y = (y < min.y) ? min.y : y;
    var z = value1.z;
    z = (z > max.z) ? max.z : z;
    z = (z < min.z) ? min.z : z;
    var vector = new ajax.math.Vector3(x, y, z);
}

//-----------------------------------------------------------------------------
ajax.math.Vector3.distanceSquared = function(vec1, vec2)
{
    var num3 = vec1.X - vec2.X;
    var num2 = vec1.Y - vec2.Y;
    var num = vec1.Z - vec2.Z;
    return (((num3 * num3) + (num2 * num2)) + (num * num));
}

//-----------------------------------------------------------------------------
ajax.math.Vector3.lengthSq = function(vec)
{
    return (vec.x * vec.x) + (vec.y * vec.y) + (vec.z * vec.z);
}
//-----------------------------------------------------------------------------
ajax.math.Vector3.prototype.lengthSq = function()
{
	return ajax.math.Vector3.lengthSq(this);
}

//-----------------------------------------------------------------------------

ajax.math.Vector3.length = function(vec)
{
    return Math.sqrt(ajax.math.Vector3.lengthSq(vec));	
}
//-----------------------------------------------------------------------------
ajax.math.Vector3.prototype.length = function()
{
    //return ajax.math.Vector3.length(this);	
    return Math.sqrt(ajax.math.Vector3.lengthSq(this));	
}

//-----------------------------------------------------------------------------
ajax.math.Vector3.dot = function(a, b)
{///<returns type="number"/>
    return (a.x*b.x) + (a.y*b.y) + (a.z*b.z);
}
//-----------------------------------------------------------------------------
ajax.math.Vector3.prototype.dot = function(b)
{///<returns type="number"/>
    return ajax.math.Vector3.dot(this, b);	
}

//-----------------------------------------------------------------------------
ajax.math.Vector3.cross = function(a, b)
{///<returns type="ajax.math.Vector3"/>
    var result = new ajax.math.Vector3();
	result.x = (a.y * b.z) - (a.z * b.y);
	result.y = (a.z * b.x) - (a.x * b.z);
	result.z = (a.x * b.y) - (a.y * b.x);
	return result;
}
//-----------------------------------------------------------------------------
ajax.math.Vector3.prototype.cross = function(b)
{///<returns type="ajax.math.Vector3"/>
	return ajax.math.Vector3.cross(this, b);
}

//-----------------------------------------------------------------------------
ajax.math.Vector3.subtract = function(a, b)
{///<returns type="ajax.math.Vector3"/>
    var result = new ajax.math.Vector3();
	result.x = a.x - b.x;
	result.y = a.y - b.y;
	result.z = a.z - b.z;
	return result;
}
//-----------------------------------------------------------------------------
ajax.math.Vector3.prototype.subtract = function(b)
{    
    this.x -= b.x;
    this.y -= b.y;
    this.z -= b.z;		
}

//-----------------------------------------------------------------------------
ajax.math.Vector3.add = function(a, b)
{///<returns type="ajax.math.Vector3"/>
	var result = new ajax.math.Vector3();
	result.x = a.x + b.x;
	result.y = a.y + b.y;
	result.z = a.z + b.z;
	return result;
}
//-----------------------------------------------------------------------------
ajax.math.Vector3.prototype.add = function(b)
{	
	this.x += b.x;
	this.y += b.y;
	this.z += b.z;
}

//-----------------------------------------------------------------------------
ajax.math.Vector3.multiply = function(a, b)
{///<returns type="ajax.math.Vector3"/>
    var result = ajax.math.Vector3.createFrom(a);
    result.x *= b.x;
    result.y *= b.y;
    result.z *= b.z;
    return result;
}
//-----------------------------------------------------------------------------
ajax.math.Vector3.prototype.multiply = function(b)
{    
    this.x *= b.x;
    this.y *= b.y;
    this.z *= b.z;
}

//-----------------------------------------------------------------------------
ajax.math.Vector3.multiplyScalar = function(a, floatScalar)
{///<returns type="ajax.math.Vector3"/>
    var result = ajax.math.Vector3.createFrom(a);
    result.x *= floatScalar;
    result.y *= floatScalar;
    result.z *= floatScalar;
    return result;
}
//-----------------------------------------------------------------------------
ajax.math.Vector3.prototype.multiplyScalar = function(floatScalar)
{    
    this.x *= floatScalar;
    this.y *= floatScalar;
    this.z *= floatScalar;    
}



//-----------------------------------------------------------------------------
ajax.math.Vector3.divide = function(a, b)
{///<returns type="ajax.math.Vector3"/>
    var result = ajax.math.Vector3.createFrom(a);
    var smallValue = 0.00001;
    result.x /= (b.x == 0) ? smallValue : b.x;
    result.y /= (b.y == 0) ? smallValue : b.y;
    result.z /= (b.z == 0) ? smallValue : b.z;
    return result;
}
//-----------------------------------------------------------------------------
ajax.math.Vector3.prototype.divide = function(b)
{    
    this.x /= b.x;
    this.y /= b.y;
    this.z /= b.z;
}

//-----------------------------------------------------------------------------
ajax.math.Vector3.divideScalar = function(a, floatScalar)
{///<returns type="ajax.math.Vector3"/>
    var result = ajax.math.Vector3.createFrom(a);
    if (floatScalar == 0)
        floatScalar = 0.00001;
    result.x /= floatScalar;
    result.y /= floatScalar;
    result.z /= floatScalar;
    return result;
}
//-----------------------------------------------------------------------------
ajax.math.Vector3.prototype.divideScalar = function(floatScalar)
{    
    this.x /= floatScalar;
    this.y /= floatScalar;
    this.z /= floatScalar;    
}

//-----------------------------------------------------------------------------
ajax.math.Vector3.transformCoordinate = function(vOriginal, mat)
{///<returns type="ajax.math.Vector3"/>
    return mat.transformVertex(vOriginal);
}
//-----------------------------------------------------------------------------
ajax.math.Vector3.prototype.transformCoordinate = function(mat)
{
    var result = ajax.math.Vector3.transformCoordinate(this, mat);
    this.x = result.x;
    this.y = result.y;
    this.z = result.z;
}

//-----------------------------------------------------------------------------
ajax.math.Vector3.transformNormal = function(normal, mat)
{///<returns type="ajax.math.Vector3"/>    
    return mat.transformNormal(normal);
}
//-----------------------------------------------------------------------------
ajax.math.Vector3.prototype.transformNormal = function(mat)
{
    var result = ajax.math.Vector3.transformNormal(this, mat);
    this.x = result.x;
    this.y = result.y;
    this.z = result.z;
}

//-----------------------------------------------------------------------------
ajax.math.Vector3.normalize = function(vec)
{///<returns type="ajax.math.Vector3"/>
    var r = new ajax.math.Vector3();
    r.copyValuesFrom(vec);
    r.normalize();
    return r;
}
//-----------------------------------------------------------------------------
ajax.math.Vector3.prototype.normalize = function()
{///<summary>Normalises this vector in place.</summary>
	var len = this.length();
	if (len == 0)
	    len = 0.000000001;
	
	this.x /= len;
	this.y /= len;
	this.z /= len;
}

//-----------------------------------------------------------------------------
ajax.math.Vector3.reflectionVector = function(vec3, normal)
{///<returns type="ajax.math.Vector3">Returns the vector reflected from the normal (as if the end of the vector hit a plane defined by the normal).</returns>
    var Vector3     = ajax.math.Vector3;    // Shortcut to namespace.
    
    // Project (shadow) the initial vector onto our normal.
    /*
    This is a handy thing about dot products: if you want to find the shadow of one vector (projection)
    onto another then you can dot it with th e unit version of the vector you want to project it against.
    Basically you can ask, "What's R in the V' direction?" Where V' is normalized.
    Therefore, the first part (-I.N') gives you a number (the -1 is just to flip the direction of I).
    But you need a vector N, so all you do is to multiply the number by the unit vector N' (vector multiplication) and,
    whammo, you have N.
    */
    var minusI      = Vector3.multiplyScalar(vec3, -1);
    var floatScalar = Vector3.dot(minusI, normal);
    var N           = Vector3.multiplyScalar(normal, floatScalar);
    
    /*
    Once you have N it's all bedrock baby...just do some vector geometry and you can find F
    
    L = N + I;
    F = N + L;
    so
    F = N + N + I;
    so
    F = 2 * N + I;
    */
    
    // return 2 * N + I (where N is the shadow of the (I)nitial Vector onto our normal).
    var ret = Vector3.add(Vector3.multiplyScalar(N, 2), vec3);
    
    return ret; 
}

//-----------------------------------------------------------------------------
ajax.math.Vector3.prototype.reflectionVector = function(normal)
{///<returns type="ajax.math.Vector3">Returns the vector reflected from the normal (as if the end of the vector hit a plane defined by the normal).</returns>
    return ajax.math.Vector3.reflectionVector(this, normal);
}

//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
ajax.math.Vector3.prototype.toString = function()
{
    return String.toFormat("x: {0}, y: {1}, z: {2}", this.x, this.y, this.z);
}

//-----------------------------------------------------------------------------
ajax.math.Vector3.cast = function(obj)
{///<returns type="ajax.math.Vector3"/>
    return obj;
}





// MS AJAX
ajax.math.Vector3.prototype.x = 0;
ajax.math.Vector3.prototype.y = 0;
ajax.math.Vector3.prototype.z = 0;
ajax.math.Vector3.prototype.sign = ajax.math.Vector3.sign;
ajax.math.Vector3.zero = function()
{///<returns type="ajax.math.Vector3"/>
    return new ajax.math.Vector3(0, 0, 0);
}
ajax.math.Vector3.up = function()
{///<returns type="ajax.math.Vector3"/>
    return new ajax.math.Vector3(0, 1, 0);
}
ajax.math.Vector3.down = function()
{///<returns type="ajax.math.Vector3"/>
    return new ajax.math.Vector3(0, -1, 0);
}
ajax.math.Vector3.left = function()
{///<returns type="ajax.math.Vector3"/>
    return new ajax.math.Vector3(-1, 0, 0);
}
ajax.math.Vector3.right = function()
{///<returns type="ajax.math.Vector3"/>
    return new ajax.math.Vector3(1, 0, 0);
}
ajax.math.Vector3.forward = function()
{///<returns type="ajax.math.Vector3"/>
    return new ajax.math.Vector3(0, 0, -1);
}
ajax.math.Vector3.backward = function()
{///<returns type="ajax.math.Vector3"/>
    return new ajax.math.Vector3(0, 0, 1);
}